package com.ikas.ai.server.module.system.service;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ikas.ai.consts.Consts;
import com.ikas.ai.server.error.BusinessException;
import com.ikas.ai.server.module.system.dao.RoleDAO;
import com.ikas.ai.server.module.system.dao.UserDAO;
import com.ikas.ai.server.module.system.model.Role;
import com.ikas.ai.server.module.system.model.User;
import com.ikas.ai.server.module.system.model.dto.ChangePasswordDTO;
import com.ikas.ai.server.module.system.model.dto.UpdateUserInfoDTO;
import com.ikas.ai.server.module.system.model.vo.UserRoleVo;
import com.ikas.ai.server.module.system.model.vo.UserVo;
import com.ikas.ai.server.security.UserContextHolder;
import com.ikas.ai.utils.DateTimeUtil;
import com.ikas.ai.utils.EncryptUtil;
import com.ikas.ai.utils.PasswordUtil;
import com.ikas.ai.utils.RedisUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@SuppressWarnings("all")
@Service
public class UserService extends ServiceImpl<UserDAO, User> {

    /**
     * 权限缓存key
     */
    private final static String PERM_KEY = Consts.PERM_CACHE_PREFIX;
    /**
     * 菜单缓存key
     */
    private final static String MENU_KEY = Consts.MENU_CACHE_PREFIX;

    @Autowired
    private UserDAO userDAO;
    @Autowired
    private RoleDAO roleDAO;
    @Autowired
    private RedisUtil redisUtil;

    /**
     * 分页查询
     *
     * @param userName
     * @param phone
     * @param email
     * @param queryTime
     * @return
     */
    public List<UserVo> pageQueryUserList(String userName, String phone, String email, String[] queryTime) {
        List<UserVo> result = new ArrayList<>();
        try {
            User user = new User();
            if (StringUtils.isNotBlank(userName)) {
                user.setUserName(userName);
            }
            if (StringUtils.isNotBlank(phone)) {
                user.setPhone(phone);
            }
            if (StringUtils.isNotBlank(email)) {
                user.setEmail(email);
            }
            if (queryTime != null && queryTime.length > 0) {
                Date stime = DateTimeUtil.getDate(queryTime[0]);
                Date etime = DateTimeUtil.getDate(queryTime[1]);
                user.setsTime(stime);
                user.seteTime(etime);
            }
            result = userDAO.listPage(user);
        } catch (Exception e) {
            log.error("查询用户分页数据出错," + e.getMessage());
        }
        return result;
    }

    /**
     * 获取用户信息
     *
     * @param userId 用户id
     * @return
     */
    public User getUserById(Long userId) {
        User user = userDAO.getUserById(userId);
        //查询用户角色信息
        List<Role> listRole = getRoleListById(userId);
        List<Long> list = listRole.stream().filter(item -> item != null).map(Role::getId).collect(Collectors.toList());
        user.setRoleId(list);
        return user;
    }


    /**
     * 获取用户信息
     *
     * @param userName
     * @return
     */
    public User getUser(String userName) {
        return userDAO.selectByUsername(userName);
//        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//        queryWrapper.lambda().eq(User::getUserName, userName);
//        return userDAO.selectOne(queryWrapper);
    }

    /**
     * 获取用户信息--包含角色信息
     *
     * @param userName
     * @return
     */
    public UserVo getUserVo(String userName) {
        return userDAO.getUser(userName);
    }

    /**
     * 保存用户信息
     *
     * @param user
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveUser(User user) {
        if (Objects.nonNull(user.getPassword()) && !PasswordUtil.validatePassword(user.getPassword())) {
            throw new BusinessException("密码长度要超过8位，且同时包含字母和数字");
        }

        user.setId(null);
        if (StringUtils.isBlank(user.getPassword())) {
            user.setPassword("ikas123456");
        }
        //如果不传值 默认则是禁用状态
        if (user.getStatus() == null) {
            user.setStatus(0);
        }
        //生成盐值
        String salt = PasswordUtil.getSalt();
        user.setSalt(salt);
        String passwordEncode = PasswordUtil.encrypt(EncryptUtil.md5(user.getPassword()), salt);
        user.setPassword(passwordEncode);
        user.setCreateTime(new Date());
        userDAO.insert(user);

        //插入用户于角色之间的关系
        List<Long> userRoleIds = user.getRoleId();
        if (userRoleIds.size() > 0) {
            roleDAO.insertUserRole(user.getId(), userRoleIds);
            //更新redis 用户权限信息
            this.updateRedis(user.getUserName());
        }
    }

    /**
     * 修改用户信息
     * 删除用于redis权限缓存信息
     *
     * @param user
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(User user) {
        if (Objects.nonNull(user.getPassword()) && !PasswordUtil.validatePassword(user.getPassword())) {
            throw new BusinessException("密码长度要超过8位，且同时包含字母和数字");
        }
        String userName = user.getUserName();
        String password = user.getPassword();
        if (StringUtils.isNotBlank(password)) {
            //生成盐值
            String salt = PasswordUtil.getSalt();
            user.setSalt(salt);
            String passwordEncode = PasswordUtil.encrypt(EncryptUtil.md5(user.getPassword()), salt);
            user.setPassword(passwordEncode);
        } else {
            //不做修改的字段都必须设置为null，如果为""的话则会被修改为""
            user.setPassword(null);
            user.setSalt(null);
        }
        //不允许用户修改登录账号
        userDAO.updateById(user);

        //更新用户所对应的角色
        List<Long> roles = user.getRoleId();
        if (roles != null && roles.size() > 0) {
            Long userId = user.getId();
            //先删除原来的用户角色关系，然后再插入新的用户角色关系
            roleDAO.deleteRoleByUserId(userId);
            roleDAO.insertUserRole(userId, user.getRoleId());
            //更新redis 用户权限信息
            this.updateRedis(userName);
        }
        //如果修改了密码 需要重新登录
        if (StringUtils.isNotBlank(password)) {
            if (redisUtil.haskey(Consts.PREFIX_USER_LOGIN + userName)) {
                redisUtil.deleteKey(Consts.PREFIX_USER_LOGIN + userName);
            }
        }
    }

    /**
     * 更改用户登录时间
     *
     * @param id
     */
    public void updateUserLoginTimeById(Long id) {
        try {
            User userDto = new User();
            userDto.setId(id);
            userDto.setLastLoginTime(new Date());
            userDAO.updateById(userDto);
        } catch (Exception e) {
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * 更新用户头像
     *
     * @param user
     */
    public void updateUserAvatar(User user) {
        userDAO.updateUserAvatar(user);
    }


    /**
     * 根据用户id获取角色列表
     *
     * @param userId
     * @return
     */
    public List<Role> getRoleListById(Long userId) {
        List<Role> list = roleDAO.getRoleListById(userId);
        return list;
    }

    /**
     * 删除用户
     * 需要删除redis当前用户权限信息
     *
     * @param id 用户id
     */
    @Transactional(rollbackFor = BusinessException.class)
    public void deleteUsers(String id) {
        List<String> ids = Arrays.asList(id.split(","));
        List<String> userNames = userDAO.selectByIds(ids);
        if (userNames.contains(Consts.ROOT)) {
            throw new BusinessException("admin账户禁止删除");
        }
        if (ids.size() == 1) {
            //只删除一个
            this.removeById(id);
            //删除用户角色之间的关系
            roleDAO.deleteRoleByUserId(Long.valueOf(id));
        } else {
            //删除多个
            this.removeByIds(ids);
            for (int i = 0; i < ids.size(); i++) {
                roleDAO.deleteRoleByUserId(Long.valueOf(ids.get(i)));
            }
        }
        //删除用户权限缓存
        userNames.forEach(userName -> {
            this.updateRedis(userName);
        });
    }

    /**
     * 插入用户和角色之间的关系
     * 需要更新redis 当前用户权限信息
     *
     * @param userRoleVo
     */
    @Transactional(rollbackFor = BusinessException.class)
    public void setUserRole(UserRoleVo userRoleVo) {
        List<Long> userList = userRoleVo.getUserId();
        List<Long> roleList = userRoleVo.getRoleId();
        //删除redis用户关联的权限信息
        List<User> users = userDAO.selectBatchIds(userList);
        users.forEach(user -> {
            Long userId = user.getId();
            String userName = user.getUserName();
            //先删除用户已有得角色列表
            roleDAO.deleteRoleByUserId(userId);
            //再插入新的角色关系
            roleDAO.insertUserRole(userId, roleList);
            //更新缓存
            this.updateRedis(userName);
        });
    }

    /**
     * 获取用户列表 0禁用，1启用
     *
     * @return
     */
    public List<JSONObject> getUserList() {
        List<JSONObject> list = new ArrayList<>();
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", 1);
        List<User> users = userDAO.selectList(queryWrapper);
        users.forEach(item -> {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("userName", item.getUserName());
            jsonObject.put("realName", item.getRealName());
            jsonObject.put("userId", item.getId());
            list.add(jsonObject);
        });
        return list;
    }

    public List<Long> listUserIdByUserName(String[] userNames) {
        return lambdaQuery()
                .select(User::getId)
                .in(User::getUserName, userNames)
                .list().stream()
                .map(User::getId).collect(Collectors.toList());
    }

    /**
     * 根据角色id查询用户集合信息
     *
     * @param roleId
     * @return
     */
    public List<User> selectByRoleId(Long roleId) {
        return userDAO.selectByRoleId(roleId);
    }


    /**
     * 更新redis缓存信息
     *
     * @param userName
     */
    @Async
    public void updateRedis(String userName) {
        if (redisUtil.haskey(MENU_KEY + userName)) {
            redisUtil.deleteKey(MENU_KEY + userName);
        }
        if (redisUtil.haskey(PERM_KEY + userName)) {
            redisUtil.deleteKey(PERM_KEY + userName);
        }
        log.warn("clear cache success....");
    }

    /**
     * 获取用户名
     *
     * @param userIds 用户id集合
     * @return 结果集
     */
    public Map<Long, String> nameMap(Collection<Long> userIds) {
        if (userIds.isEmpty()) {
            return Collections.emptyMap();
        }

        return lambdaQuery().in(User::getId, userIds).list().stream()
                .collect(Collectors.toMap(User::getId, User::getUserName));
    }

    public void changePassword(ChangePasswordDTO changePasswordDTO) throws Exception {
        User user = userDAO.selectById(UserContextHolder.getTokenUser().getUserId());
        if (Objects.isNull(user)) {
            throw new BusinessException("该用户不存在！");
        }
        if (!user.getPassword().equals(PasswordUtil.encrypt(changePasswordDTO.getPrePassword(), user.getSalt()))) {
            throw new BusinessException("原密码错误！");
        }
        try {
            String userName = user.getUserName();
            String password = changePasswordDTO.getPassword();
            if (StringUtils.isNotBlank(password)) {
                //生成盐值
                String salt = PasswordUtil.getSalt();
                user.setSalt(salt);
                String passwordEncode = PasswordUtil.encrypt(password, salt);
                user.setPassword(passwordEncode);
            } else {
                //不做修改的字段都必须设置为null，如果为""的话则会被修改为""
                user.setPassword(null);
            }
            //不允许用户修改登录账号
            userDAO.updateById(user);

            //更新用户所对应的角色
            List<Long> roles = user.getRoleId();
            if (roles != null && roles.size() > 0) {
                Long userId = user.getId();
                //先删除原来的用户角色关系，然后再插入新的用户角色关系
                roleDAO.deleteRoleByUserId(userId);
                roleDAO.insertUserRole(userId, user.getRoleId());
                //更新redis 用户权限信息
                this.updateRedis(userName);
            }
            //如果修改了密码 需要重新登录
            if (StringUtils.isNotBlank(password)) {
                if (redisUtil.haskey(Consts.PREFIX_USER_LOGIN + userName)) {
                    redisUtil.deleteKey(Consts.PREFIX_USER_LOGIN + userName);
                }
            }
        } catch (Exception e) {
            throw new BusinessException("修改用户信息出错，" + e.getMessage());
        }
    }

    public void updateUserInfo(UpdateUserInfoDTO userInfoDTO, User currUser) {
        if (!currUser.getId().equals(userInfoDTO.getId())) {
            throw new BusinessException("只能修改个人信息！");
        }
        User user = userDAO.selectById(userInfoDTO.getId());
        if (Objects.isNull(user)) {
            throw new BusinessException("该用户不存在！");
        }
        try {
            String userName = userInfoDTO.getUsername();
            //不做修改的字段都必须设置为null，如果为""的话则会被修改为""
            org.springframework.beans.BeanUtils.copyProperties(userInfoDTO, user);
            user.setPassword(null);
            user.setUserName(userName);
            //不允许用户修改登录账号
            userDAO.updateById(user);
            //更新用户所对应的角色
            List<Long> roles = user.getRoleId();
            if (roles != null && roles.size() > 0) {
                Long userId = user.getId();
                //先删除原来的用户角色关系，然后再插入新的用户角色关系
                roleDAO.deleteRoleByUserId(userId);
                roleDAO.insertUserRole(userId, user.getRoleId());
                //更新redis 用户权限信息
                this.updateRedis(userName);
            }
        } catch (Exception e) {
            throw new BusinessException("修改用户信息出错，" + e.getMessage());
        }
    }
}
